﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet.Core;
using MQTTnet.Core.Client;
using MQTTnet.Core.Packets;

namespace ComTools
{
    public partial class frmMQTT : Form
    {
        public frmMQTT()
        {
            InitializeComponent();
        }

        IMqttClient mqttClient = null;

        private async void init()
        {

            mqttClient = new MQTTnet.MqttClientFactory().CreateMqttClient();

            MqttClientTcpOptions clientTcpOptions = new MqttClientTcpOptions();

            clientTcpOptions.Server = txtServer.Text.Trim();
            if (!String.IsNullOrEmpty(txtPorts.Text))
            {
                clientTcpOptions.Port = int.Parse(txtPorts.Text.Trim());
            }
            clientTcpOptions.ClientId = txtClientID.Text.Trim();
            clientTcpOptions.UserName = txtUserName.Text.Trim();
            clientTcpOptions.Password = txtPassword.Text.Trim();
            clientTcpOptions.CleanSession = true;

            mqttClient.Connected += MqttClient_Connected;
            mqttClient.Disconnected += MqttClient_Disconnected;

            await mqttClient.ConnectAsync(clientTcpOptions);

        }

        private void MqttClient_Disconnected(object sender, EventArgs e)
        {
            OutLog("has disconnected");
        }

        private void MqttClient_Connected(object sender, EventArgs e)
        {
            OutLog("has connected");
        }

        private String GetParameterStr()
        {
            decimal value = decimal.Parse(txtValue.Text.Trim());

            DateTime dt = DateTime.Parse(txtDateTime.Text.Trim());
            int utc = UTCClass.DateTime2Int(dt);

            var xx = new
            {
                applicationId = 54,
                companyId = 11,
                createTime = utc * 1000,
                data = new
                {
                    activateSuccessCnt = 73,
                    otaVersion = "3.4.7",
                    commInitFailCnt = 0,
                    electricity = 94.92,
                    uploadDataCnt = 0,
                    areasInfo = 229,
                    effectiveValue = 0,
                    aIoCRunCnt = 73,
                    sleepCnt = 0,
                    timeoutCnt = 0,
                    activateFailCnt = 0,
                    commInitSuccessCnt = 73,
                    signal = -100.9,
                    value = value,
                    signalNoise = 8.5,
                    wakenCnt = 43,
                    signalECL = 0
                },
                dataTypeId = 160,
                deviceName = txtDeviceName.Text.Trim(),
                deviceSecret = "aM7jZBlXPN3W1UGrvhsjZzkwQWeQNQlS",
                deviceTypeCode = 160,
                eventId = 1,
                networkType = 2,
                periodId = Guid.NewGuid().ToString(),
                productKey = "gdAqq0OR1bH",
                requestId = Guid.NewGuid().ToString(),
                timeStamp = utc,
                version = 3
            };

            String content = Newtonsoft.Json.JsonConvert.SerializeObject(xx);

            return content;
        }

        private async void BtnSendClient_Click(object sender, EventArgs e)
        {
            if (mqttClient != null)
            {
                String content = txtContent.Text.Trim();
                if (String.IsNullOrEmpty(content))
                {
                    return;
                }

                byte[] data = Encoding.UTF8.GetBytes(content);

                await mqttClient.PublishAsync(new List<MqttApplicationMessage>(){
                    new MqttApplicationMessage(txtTopics.Text.Trim(), data, MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.AtMostOnce, true)
                });

                OutLog("Has Published");
            }
        }

        private void FrmMQTT_Load(object sender, EventArgs e)
        {
            txtClientID.Text = Guid.NewGuid().ToString();
            txtDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }

        private void BtnInitMqtt_Click(object sender, EventArgs e)
        {
            init();
        }

        private async void BtnSubscribe_Click(object sender, EventArgs e)
        {
            if (mqttClient != null)
            {
                mqttClient.ApplicationMessageReceived += MqttClient_ApplicationMessageReceived;

                await mqttClient.SubscribeAsync(new List<TopicFilter>() {
                    new TopicFilter(txtTopics.Text.Trim(), MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.AtMostOnce)
                });
                //
                OutLog("Has Subscribed");
            }
        }

        private void MqttClient_ApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        {
            String content = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
            textBox1.Invoke(new MethodInvoker(() =>
            {
                textBox1.AppendText(content);
                textBox1.AppendText(Environment.NewLine);
            }));
        }

        MethodInvoker methodInvoker = null;

        private void OutLog(String msg)
        {
            if (this.InvokeRequired)
            {
                if (methodInvoker == null)
                {
                    methodInvoker = new MethodInvoker(() =>
                    {
                        txtLog.AppendText(msg);
                        txtLog.AppendText(Environment.NewLine);
                    });
                }
                //
                this.Invoke(methodInvoker);
            }
            else
            {
                txtLog.AppendText(msg);
                txtLog.AppendText(Environment.NewLine);
            }
        }

        MethodInvoker miParameters = null;
        private void StepDatetime()
        {
            if (miParameters == null)
            {
                miParameters = new MethodInvoker(() =>
                {
                    int interval = int.Parse(txtInterval.Text.Trim());
                    DateTime dt = DateTime.Parse(txtDateTime.Text.Trim());
                    txtDateTime.Text = dt.AddSeconds(interval).ToString("yyyy-MM-dd HH:mm:ss");
                });
            }
            this.Invoke(miParameters);

        }

        MethodInvoker miStepStep = null;
        private void StepStepValue()
        {
            if (miStepStep == null)
            {
                miStepStep = new MethodInvoker(() =>
                {
                    decimal dStep = decimal.Parse(txtValueStep.Text.Trim());
                    decimal dValue = decimal.Parse(txtValue.Text.Trim());
                    dValue += dStep;
                    //int valueStep = int.Parse(txtValueStep.Text.Trim());
                    //int value = int.Parse(txtValue.Text.Trim());
                    //value += valueStep;
                    txtValue.Text = dValue.ToString();
                });
            }
            this.Invoke(miStepStep);
        }

        System.Threading.Timer timer = null;

        private void BtnAutoPublish_Click(object sender, EventArgs e)
        {
            timer = new System.Threading.Timer(new System.Threading.TimerCallback((obj) =>
            {
                StepDatetime();
                StepStepValue();
                SinglePublish();
            }), null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

            int interval = int.Parse(txtInterval.Text.Trim()) * 1000;

            timer.Change(1000, interval);
        }

        private void SinglePublish()
        {
            //
            String json = GetParameterStr();
            byte[] data = Encoding.UTF8.GetBytes(json);

            mqttClient.PublishAsync(new List<MqttApplicationMessage>(){
                        new MqttApplicationMessage(txtTopics.Text.Trim(), data, MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.AtMostOnce, true)
                    });

            OutLog("has published a message");
        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            if (timer != null)
            {
                timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
                OutLog("has stop autopublish");
            }
        }

        private void btnSinglePublish_Click(object sender, EventArgs e)
        {
            SinglePublish();
        }
    }
}